import { merge, errorHandle, getErrorMessage } from "utils";
import { throwIfCancellationRequested, isCancelRequest, isDropError } from "../tool";
import { CancelError, DropError } from "../../error";
import type { InnerRequestConfig } from "../../types/engine.type";

// 准备请求
const requestFunc = async (
    config: InnerRequestConfig
): Promise<{
    task: UniApp.RequestTask | null;
    response: any;
}> => {
    // 检查  是否要 取消了
    let cancelPromise = throwIfCancellationRequested(config);
    if (cancelPromise) {
        return cancelPromise;
    }
    // 合并header
    let header = merge(config.header ?? {}, config.baseHeader ?? {});
    // 合并data
    let data = merge(config.data ?? {}, config.baseData ?? {});

    // url 和 query
    let url = `${config.baseURL ?? ""}${config.path ?? ""}`;
    let requestQuery = config.query;
    if (requestQuery) {
        let queryString = Object.keys(requestQuery)
            .map((e) => {
                let value = requestQuery[e] || "";
                return `${e}=${encodeURIComponent(value)}`;
            })
            .join("&");
        if (queryString.length > 0) {
            url = `${url}?${queryString}`;
        }
    }
    const { readyToRequest } = config || {};
    // 发起请求
    return new Promise((resolve, reject) => {
        let reqTask: UniApp.RequestTask | null = null;
        const callBackSuccess = (res: any) => {
            resolve({
                task: reqTask,
                response: res,
            });
        };
        const callBackFail = (err: any) => {
            let msg = getErrorMessage(err);
            let errMsg: string | null = typeof msg === "string" ? msg : null;
            // 判断是不是取消的请求
            let isCancel = isCancelRequest(config, errMsg);
            if (isCancel) {
                let reason = config.cancelToken?.reason;
                reject(new CancelError(reason));
                return;
            }
            // 超时 或者 没有网络
            let isDrop = isDropError(errMsg);
            if (isDrop) {
                reject(new DropError());
                return;
            }
            let insideErr = errorHandle.insideErr(err);
            reject(insideErr);
        };
        //
        let method = config.method || "GET";
        let targetMethod: "GET" | "POST" = method === "none" ? "GET" : method;
        // 要请求了
        let param = {
            url,
            header,
            data,
            method: targetMethod,
            // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY
            timeout: config.timeout || 60000,
            // #endif
            dataType: config.dataType ?? "json",

            // #ifndef MP-ALIPAY
            // 支付宝不支持
            responseType: config.responseType ?? "text",
            // #endif

            // 请求 完成
            success: callBackSuccess,
            fail: callBackFail,
        };
        // 准备 请求
        readyToRequest && readyToRequest(config);
        reqTask = uni.request(param);
        if (config.cancelToken && reqTask) {
            config.cancelToken.promise.then(() => {
                reqTask.abort();
            });
        }
    });
};

export { requestFunc };
